package com.huilian.iotbox.data.service.impl;


import com.alibaba.fastjson.JSON;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.dao.PushConfigCommonDao;
import com.huilian.iotbox.data.enums.AttributeEnum;
import com.huilian.iotbox.data.enums.PushConfigTypeEnum;
import com.huilian.iotbox.data.enums.PushRecordResultEnum;
import com.huilian.iotbox.data.po.AppletOrOfficialAccount;
import com.huilian.iotbox.data.po.PushConfigTemplate;
import com.huilian.iotbox.data.po.PushRecord;
import com.huilian.iotbox.data.po.User;
import com.huilian.iotbox.data.properties.ConfigProperties;
import com.huilian.iotbox.data.service.*;
import com.huilian.iotbox.data.vo.MerchantStoreVo;
import com.huilian.iotbox.data.vo.PushConfigVo;
import com.huilian.tool.applet.wechat.service.WeChatAppletService;
import com.huilian.tool.weixin.service.WXSendMessageService;
import com.huilian.tool.weixin.service.WeixinService;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class WXSendMessageServiceImpl implements WXSendMessageService {

    private static int officialAccount = 1;
    private static int applet = 2;

    @Autowired
    private HttpService httpService;
    @Autowired
    private UserCommonService userCommonService;
    @Autowired
    private WeixinService weixinService;
    @Autowired
    private ConfigProperties configProperties;
    @Autowired
    private PushConfigCommonDao pushConfigCommonDao;
    @Autowired
    private WeChatAppletService weChatAppletService;
    @Autowired
    private ErrorLogCommonService errorLogCommonService;
    @Autowired
    private PushRecordCommonService pushRecordCommonService;
    @Autowired
    private MerchantStoreCommonService merchantStoreCommonService;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;
    @Autowired
    private PushConfigTemplateCommonService pushConfigTemplateCommonService;
    @Autowired
    private AppletOrOfficialAccountCommonService appletOrOfficialAccountCommonService;

    //developer为开发版；trial为体验版；formal为正式版；默认为正式版
    @Value("${notify.applet.dev}")
    private String dev;

    /**
     * 出货失败
     *
     * @param deviceNo        设备号
     * @param outTradeNo      订单号
     * @param goodsName       商品名称
     * @param deviceId        设备ID
     * @param baseUserId      商家ID
     * @param orderId         订单ID
     * @param merchantStoreId
     */
    @Override
    public void sendVendingShipmentFailMessage(
            String deviceNo,
            String outTradeNo,
            String goodsName,
            Integer deviceId,
            Integer baseUserId,
            Long orderId,
            Integer merchantStoreId
    ) {
        try {
            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(baseUserId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                if (!StringUtils.isEmpty(u.getParentId())) {
                    final MerchantStoreVo merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletAccountVendingShipmentFail(deviceNo, outTradeNo, goodsName, deviceId, orderId, u, baseUserId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.officialAccountVendingShipmentFail(deviceNo, outTradeNo, goodsName, deviceId, orderId, u, baseUserId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("通知发送异常", null, e);
        }
    }

    /**
     * 小程序，出货失败通知
     *
     * @param deviceNo
     * @param outTradeNo
     * @param goodsName
     * @param deviceId
     * @param orderId
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void appletAccountVendingShipmentFail(
            String deviceNo,
            String outTradeNo,
            String goodsName,
            Integer deviceId,
            Long orderId, User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {

    }

    /**
     * 公众号，出货失败通知
     *
     * @param deviceNo
     * @param outTradeNo
     * @param goodsName
     * @param deviceId
     * @param orderId
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void officialAccountVendingShipmentFail(
            String deviceNo,
            String outTradeNo,
            String goodsName,
            Integer deviceId,
            Long orderId, User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.EXCEPTION_ORDER.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, user.getId(), user.getOfficialAccountId(), pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(user.getOfficialAccountId());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", user.getOfficialAccountOpenId());
        JSONObject item = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", deviceNo);
        item.put("character_string1", keyword1);
        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", outTradeNo);
        item.put("character_string2", keyword2);
        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", goodsName);
        item.put("thing3", keyword3);
        JSONObject keyword4 = new JSONObject();
        keyword4.put("value", sdf.format(new Date()));
        item.put("time4", keyword4);
        log.info(JSON.toJSONString(item));
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();
            if (!StringUtils.isEmpty(user.getAppletAccountId())) {
                final AppletOrOfficialAccount appletAccount = appletOrOfficialAccountCommonService.findOneById(user.getAppletAccountId());
                miniprogram.put("appid", appletAccount.getWeChatAppId());
            } else {
                miniprogram.put("appid", configProperties.getWapAppletAppId());
            }
            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), deviceId));
            jsonObject.put("miniprogram", miniprogram);
        }
        jsonObject.put("data", item);
        this.sendOfficialAccount(
                jsonObject,
                user.getOfficialAccountOpenId(),
                appletOrOfficialAccount,
                baseUserId,
                user.getId(),
                merchantStoreId,
                pushConfigType
        );
    }


    /**
     * 设备离线通知
     *
     * @param deviceNo
     * @param storeName
     * @param deviceId
     * @param baseUserId
     * @param merchantStoreId
     */
    @Override
    public void sendOfflineMessage(
            String deviceNo,
            String storeName,
            Integer deviceId,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        try {
            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(baseUserId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                if (!StringUtils.isEmpty(u.getParentId())) {
                    final MerchantStoreVo merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletAccountTen(deviceNo, storeName, u.getId(), u.getAppletAccountId(), u.getAppletAccountOpenId(), baseUserId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.officialAccountTen(deviceNo, storeName, u.getId(), u.getOfficialAccountId(), u.getOfficialAccountOpenId(), baseUserId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("设备离线通知发送异常", null, e);
        }
    }

    /**
     * 小程序，设备离线通知
     *
     * @param deviceNo
     * @param storeName
     * @param userId
     * @param appletAccountId
     * @param appletAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     * @throws Exception
     */
    private void appletAccountTen(
            String deviceNo,
            String storeName,
            Integer userId,
            Integer appletAccountId,
            String appletAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) throws Exception {
        final int pushConfigType = PushConfigTypeEnum.THE_DEVICE_IS_OFFLINE.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(applet, userId, appletAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final String key = String.format(RedisKey.NOTICE_RESTRICTIONS, userId, deviceNo, applet);
        if (Boolean.TRUE.equals(redisCacheTemplate.hasKey(key))) {
            log.warn("发送冷却中");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletAccountId);
        redisCacheTemplate.opsForValue().set(key, PushConfigTypeEnum.THE_DEVICE_IS_OFFLINE.getCode(), pushConfigVo.getInterval(), TimeUnit.SECONDS);

        // 处理微信推送数据结构 这里每个模板的数据不一样，参数不一样
        //设备离线
        JSONObject mapData = new JSONObject();
        JSONObject data = new JSONObject();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        JSONObject d = new JSONObject();
        d.put("value", deviceNo);
        data.put("character_string13", d);

        JSONObject s = new JSONObject();
        s.put("value", storeName);
        data.put("thing9", s);

        JSONObject time = new JSONObject();
        time.put("value", sdf.format(new Date()));
        data.put("time3", time);

        mapData.put("template_id", pushConfigVo.getTemplateId());// 模板 id
        mapData.put("touser", appletAccountOpenId); // openId
        mapData.put("data", data); // 数据
        mapData.put("page", ""); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
        mapData.put("miniprogram_state", dev); //developer为开发版；trial为体验版；formal为正式版；默认为正式版
        mapData.put("lang", "zh_CN");

        this.sendApplet(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 公众号，设备离线通知
     *
     * @param deviceNo
     * @param storeName
     * @param userId
     * @param officialAccountId
     * @param officialAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     */
    private void officialAccountTen(
            String deviceNo,
            String storeName,
            Integer userId,
            Integer officialAccountId,
            String officialAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.THE_DEVICE_IS_OFFLINE.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, userId, officialAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final String key = String.format(RedisKey.NOTICE_RESTRICTIONS, userId, deviceNo, officialAccount);
        if (Boolean.TRUE.equals(redisCacheTemplate.hasKey(key))) {
            log.warn("发送冷却中");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(officialAccountId);
        redisCacheTemplate.opsForValue().set(key, PushConfigTypeEnum.THE_DEVICE_IS_OFFLINE.getCode(), pushConfigVo.getInterval(), TimeUnit.SECONDS);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", officialAccountOpenId);
        JSONObject item = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", deviceNo);
        item.put("thing6", keyword1);
        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", storeName);
        item.put("thing7", keyword2);
        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", sdf.format(new Date()));
        item.put("time4", keyword3);
        log.info(JSON.toJSONString(item));
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();

            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), deviceNo));
            jsonObject.put("miniprogram", miniprogram);
        }
        jsonObject.put("data", item);
        this.sendOfficialAccount(
                jsonObject,
                officialAccountOpenId,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 下单成功通知
     *
     * @param outTradeNo
     * @param paymentAmount
     * @param goodsName
     * @param deviceNo
     * @param userId
     * @param orderId
     * @param merchantStoreId
     * @param gmtPayment
     */
    @Override
    public void sendTheOrderWasPlacedMessage(
            String outTradeNo,
            BigDecimal paymentAmount,
            String goodsName,
            String deviceNo,
            Integer userId,
            Long orderId,
            Integer merchantStoreId,
            Date gmtPayment
    ) {
        try {
            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(userId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                MerchantStoreVo merchantStoreVo = null;
                if (!StringUtils.isEmpty(u.getParentId())) {
                    merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletAccountFive(outTradeNo, gmtPayment, paymentAmount, goodsName, orderId, u.getId(), merchantStoreVo.getStoreName(), u.getAppletAccountId(), u.getAppletAccountOpenId(), userId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.officialAccountFive(outTradeNo, paymentAmount, goodsName, deviceNo, merchantStoreVo.getStoreName(), orderId, u, userId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("下单成功通知发送异常", null, e);
        }
    }

    /**
     * 小程序，下单成功通知
     *
     * @param outTradeNo
     * @param gmtPayment
     * @param paymentAmount
     * @param goodsName
     * @param orderId
     * @param userId
     * @param storeName
     * @param appletAccountId
     * @param appletAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     * @throws Exception
     */
    private void appletAccountFive(
            String outTradeNo,
            Date gmtPayment,
            BigDecimal paymentAmount,
            String goodsName,
            Long orderId, Integer userId,
            String storeName,
            Integer appletAccountId,
            String appletAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) throws Exception {
        final int pushConfigType = PushConfigTypeEnum.SCAN_THE_CODE_TO_PLACE_AN_ORDER_SUCCESSFULLY.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(applet, userId, appletAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletAccountId);

        JSONObject mapData = new JSONObject();
        JSONObject data = new JSONObject();
        JSONObject orderNo01 = new JSONObject();
        orderNo01.put("value", outTradeNo);
        data.put("character_string1", orderNo01);

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formattedDate = dateFormat.format(gmtPayment);
        JSONObject time13 = new JSONObject();
        time13.put("value", formattedDate);
        data.put("time13", time13);

        JSONObject amount12 = new JSONObject();
        BigDecimal roundedValue = paymentAmount.setScale(2, RoundingMode.HALF_UP);
        amount12.put("value", roundedValue);
        data.put("amount12", amount12);

        JSONObject thing14 = new JSONObject();
        thing14.put("value", goodsName);
        data.put("thing14", thing14);

        JSONObject thing10 = new JSONObject();
        thing10.put("value", storeName);
        data.put("thing10", thing10);
        mapData.put("template_id", pushConfigVo.getTemplateId());// 模板 id
        mapData.put("touser", appletAccountOpenId); // openId
        mapData.put("data", data); // 数据
        mapData.put("page", ""); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
        mapData.put("miniprogram_state", dev);
        mapData.put("lang", "zh_CN");
        log.info("mapData{}", mapData);

        log.warn("发送成功-----------------");
        this.sendApplet(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 公众号，下单成功通知
     *
     * @param outTradeNo
     * @param paymentAmount
     * @param goodsName
     * @param deviceNo
     * @param storeName
     * @param orderId
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void officialAccountFive(
            String outTradeNo,
            BigDecimal paymentAmount,
            String goodsName,
            String deviceNo,
            String storeName,
            Long orderId, User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.SCAN_THE_CODE_TO_PLACE_AN_ORDER_SUCCESSFULLY.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, user.getId(), user.getOfficialAccountId(), pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(user.getOfficialAccountId());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", user.getOfficialAccountOpenId());
        JSONObject item = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", outTradeNo);
        item.put("character_string9", keyword1);
        BigDecimal roundedValue = paymentAmount.setScale(2, RoundingMode.HALF_UP);
        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", roundedValue);
        item.put("amount8", keyword2);
        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", deviceNo);
        item.put("thing5", keyword3);
        JSONObject keyword4 = new JSONObject();
        keyword4.put("value", goodsName);
        item.put("thing7", keyword4);
        JSONObject keyword5 = new JSONObject();
        keyword5.put("value", sdf.format(new Date()));
        item.put("time4", keyword5);
        log.info(JSON.toJSONString(item));

        // 获取当前日期和时间
        Date currentDate = new Date();

        // 创建Calendar对象，并将日期设置为当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);

        // 将月份减去1，即得到一个月前的日期
        calendar.add(Calendar.MONTH, -1);

        // 获取一个月前的日期
        Date oneMonthAgo = calendar.getTime();
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();
            if (!StringUtils.isEmpty(user.getAppletAccountId())) {
                final AppletOrOfficialAccount appletAccount = appletOrOfficialAccountCommonService.findOneById(user.getAppletAccountId());
                miniprogram.put("appid", appletAccount.getWeChatAppId());
            } else {
                miniprogram.put("appid", configProperties.getWapAppletAppId());
            }
            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), outTradeNo, oneMonthAgo));
            jsonObject.put("miniprogram", miniprogram);
        }

        jsonObject.put("data", item);

        log.warn("发送成功-----------------");
        this.sendOfficialAccount(
                jsonObject,
                user.getOfficialAccountOpenId(),
                appletOrOfficialAccount,
                baseUserId,
                user.getId(),
                merchantStoreId,
                pushConfigType
        );
    }


    /**
     * 出货成功通知
     *
     * @param goodsName
     * @param deviceNo
     * @param location
     * @param storeName
     * @param userId
     * @param merchantStoreId
     */
    @Override
    public void sendVendingShipmentSuccessMessage(
            String goodsName,
            String deviceNo,
            String location,
            String storeName,
            Integer userId,
            Integer merchantStoreId
    ) {
        try {
            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(userId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                if (!StringUtils.isEmpty(u.getParentId())) {
                    final MerchantStoreVo merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletAccountVendingShipmentSuccess(goodsName, deviceNo, location, storeName, u.getId(), u.getAppletAccountId(), u.getAppletAccountOpenId(), userId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.officialAccountVendingShipmentSuccess(goodsName, deviceNo, location, storeName, u, userId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("出货成功通知发送异常", null, e);
        }
    }

    /**
     * 小程序 出货成功通知
     *
     * @param goodsName
     * @param deviceNo
     * @param location
     * @param storeName
     * @param userId
     * @param appletAccountId
     * @param appletAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     * @throws Exception
     */
    private void appletAccountVendingShipmentSuccess(
            String goodsName,
            String deviceNo,
            String location,
            String storeName,
            Integer userId,
            Integer appletAccountId,
            String appletAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) throws Exception {
        final int pushConfigType = PushConfigTypeEnum.SHIPMENT_SUCCESSFUL.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(applet, userId, appletAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletAccountId);

        JSONObject mapData = new JSONObject();
        JSONObject data = new JSONObject();
        JSONObject thing1 = new JSONObject();
        thing1.put("value", goodsName);
        data.put("thing1", thing1);

        JSONObject characterString2 = new JSONObject();
        characterString2.put("value", deviceNo);
        data.put("character_string2", characterString2);

        JSONObject characterString3 = new JSONObject();
        characterString3.put("value", location);
        data.put("character_string3", characterString3);

        JSONObject thing4 = new JSONObject();
        thing4.put("value", storeName);
        data.put("thing4", thing4);

        JSONObject thing12 = new JSONObject();
        thing12.put("value", goodsName);
        data.put("thing12", thing12);

        JSONObject time5 = new JSONObject();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        time5.put("value", sdf.format(new Date()));
        data.put("time5", time5);

        mapData.put("template_id", pushConfigVo.getTemplateId());// 模板 id
        mapData.put("touser", appletAccountOpenId); // openId
        mapData.put("data", data); // 数据
        mapData.put("page", ""); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
        mapData.put("miniprogram_state", dev); //developer为开发版；trial为体验版；formal为正式版；默认为正式版
        mapData.put("lang", "zh_CN");
        log.info("mapData{}", mapData);

        this.sendApplet(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 公众号 出货成功通知
     *
     * @param goodsName
     * @param deviceNo
     * @param location
     * @param storeName
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void officialAccountVendingShipmentSuccess(
            String goodsName,
            String deviceNo,
            String location,
            String storeName,
            User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.SHIPMENT_SUCCESSFUL.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, user.getId(), user.getOfficialAccountId(), pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(user.getOfficialAccountId());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", user.getOfficialAccountOpenId());
        JSONObject item = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", goodsName);
        item.put("thing4", keyword1);
        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", deviceNo);
        item.put("character_string9", keyword2);
        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", location);
        item.put("character_string8", keyword3);
        JSONObject keyword4 = new JSONObject();
        keyword4.put("value", storeName);
        item.put("thing2", keyword4);
        JSONObject keyword5 = new JSONObject();
        keyword5.put("value", sdf.format(new Date()));
        item.put("time1", keyword5);
        log.info(JSON.toJSONString(item));
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();
            if (!StringUtils.isEmpty(user.getAppletAccountId())) {
                final AppletOrOfficialAccount appletAccount = appletOrOfficialAccountCommonService.findOneById(user.getAppletAccountId());
                miniprogram.put("appid", appletAccount.getWeChatAppId());
            } else {
                miniprogram.put("appid", configProperties.getWapAppletAppId());
            }
            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), deviceNo));
            jsonObject.put("miniprogram", miniprogram);
        }

        jsonObject.put("data", item);
        this.sendOfficialAccount(
                jsonObject,
                user.getOfficialAccountOpenId(),
                appletOrOfficialAccount,
                baseUserId,
                user.getId(),
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 库存通知
     *
     * @param deviceNo
     * @param deviceId
     * @param location
     * @param num
     * @param storeName
     * @param goodsName
     * @param userId
     * @param orderId
     * @param merchantStoreId
     */
    @Override
    public void sendVendingMachineOutOfStockMessage(
            String deviceNo,
            Integer deviceId,
            String location,
            int num,
            String storeName,
            String goodsName,
            Integer userId,
            Long orderId,
            Integer merchantStoreId
    ) {
        try {

            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(userId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                if (!StringUtils.isEmpty(u.getParentId())) {
                    final MerchantStoreVo merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletAccountSixteen(deviceNo, location, num, storeName, goodsName, orderId, u.getId(), u.getAppletAccountId(), u.getAppletAccountOpenId(), userId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.officialAccountSixteen(deviceNo, deviceId, location, num, storeName, goodsName, orderId, u, userId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("库存通知发送异常", null, e);
        }
    }

    /**
     * 小程序 库存通知
     *
     * @param deviceNo
     * @param location
     * @param num
     * @param storeName
     * @param goodsName
     * @param orderId
     * @param userId
     * @param appletAccountId
     * @param appletAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     * @throws Exception
     */
    private void appletAccountSixteen(
            String deviceNo,
            String location,
            int num,
            String storeName,
            String goodsName,
            Long orderId, Integer userId,
            Integer appletAccountId,
            String appletAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) throws Exception {
        final int pushConfigType = PushConfigTypeEnum.VENDING_MACHINE_INVENTORY.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(applet, userId, appletAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletAccountId);

        //商品库存通知
        JSONObject mapData = new JSONObject();
        JSONObject data = new JSONObject();
        JSONObject d = new JSONObject();
        d.put("value", deviceNo);
        data.put("character_string10", d);

        JSONObject hao = new JSONObject();
        hao.put("value", location);
        data.put("character_string3", hao);

        JSONObject number9 = new JSONObject();
        number9.put("value", num);
        data.put("number9", number9);

        JSONObject thing11 = new JSONObject();
        thing11.put("value", storeName);
        data.put("thing11", thing11);

        JSONObject thing12 = new JSONObject();
        thing12.put("value", goodsName);
        data.put("thing12", thing12);

        mapData.put("template_id", pushConfigVo.getTemplateId());// 模板 id
        mapData.put("touser", appletAccountOpenId); // openId
        mapData.put("data", data); // 数据
        mapData.put("page", ""); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
        mapData.put("miniprogram_state", dev); //developer为开发版；trial为体验版；formal为正式版；默认为正式版
        mapData.put("lang", "zh_CN");
        log.info("mapData{}", mapData);

        this.sendApplet(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 公众号 库存通知
     *
     * @param deviceNo
     * @param deviceId
     * @param location
     * @param num
     * @param storeName
     * @param goodsName
     * @param orderId
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void officialAccountSixteen(
            String deviceNo,
            Integer deviceId,
            String location,
            int num,
            String storeName,
            String goodsName,
            Long orderId, User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.SHIPMENT_SUCCESSFUL.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, user.getId(), user.getOfficialAccountId(), pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(user.getOfficialAccountId());

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", user.getOfficialAccountOpenId());
        JSONObject item = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", deviceNo);
        item.put("character_string1", keyword1);
        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", location);
        item.put("character_string3", keyword2);
        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", num);
        item.put("character_string4", keyword3);
        JSONObject keyword4 = new JSONObject();
        keyword4.put("value", storeName);
        item.put("thing5", keyword4);
        item.put("character_string4", keyword3);
        JSONObject keyword5 = new JSONObject();
        keyword5.put("value", goodsName);
        item.put("thing6", keyword5);
        log.info(JSON.toJSONString(item));
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();
            if (!StringUtils.isEmpty(user.getAppletAccountId())) {
                final AppletOrOfficialAccount appletAccount = appletOrOfficialAccountCommonService.findOneById(user.getAppletAccountId());
                miniprogram.put("appid", appletAccount.getWeChatAppId());
            } else {
                miniprogram.put("appid", configProperties.getWapAppletAppId());
            }
            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), deviceId));
            jsonObject.put("miniprogram", miniprogram);
        }
        jsonObject.put("data", item);
        this.sendOfficialAccount(
                jsonObject,
                user.getOfficialAccountOpenId(),
                appletOrOfficialAccount,
                baseUserId,
                user.getId(),
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 售货机电量通知
     *
     * @param deviceNo
     * @param power
     * @param time
     * @param userId
     * @param merchantStoreId
     * @param merchantStoreName
     */
    @Override
    public void sendVendingPowerMessage(
            String deviceNo,
            String power,
            Date time,
            Integer userId,
            Integer merchantStoreId,
            String merchantStoreName
    ) {
        try {
            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(userId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                if (!StringUtils.isEmpty(u.getParentId())) {
                    final MerchantStoreVo merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletLowBatteryNotification(deviceNo, power, time, u.getId(), u.getAppletAccountId(), u.getAppletAccountOpenId(), userId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.officialLowBatteryNotification(deviceNo, power, time, merchantStoreName, u, userId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("售货机电量通知发送异常", null, e);
        }
    }

    /**
     * 小程序 低电量通知
     *
     * @param deviceNo
     * @param power
     * @param time
     * @param userId
     * @param appletAccountId
     * @param appletAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     * @throws Exception
     */
    private void appletLowBatteryNotification(
            String deviceNo,
            String power,
            Date time,
            Integer userId,
            Integer appletAccountId,
            String appletAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) throws Exception {
        final int pushConfigType = PushConfigTypeEnum.VENDING_MACHINE_POWER.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(applet, userId, appletAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletAccountId);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        JSONObject mapData = new JSONObject();
        JSONObject data = new JSONObject();
        JSONObject d = new JSONObject();
        d.put("value", deviceNo);
        data.put("thing1", d);

        JSONObject hao = new JSONObject();
        hao.put("value", power);
        data.put("character_string4", hao);

        JSONObject number9 = new JSONObject();
        number9.put("value", sdf.format(time));
        data.put("time3", number9);

        mapData.put("template_id", pushConfigVo.getTemplateId());// 模板 id
        mapData.put("touser", appletAccountOpenId); // openId
        mapData.put("data", data); // 数据
        mapData.put("page", ""); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
        mapData.put("miniprogram_state", dev); //developer为开发版；trial为体验版；formal为正式版；默认为正式版
        mapData.put("lang", "zh_CN");
        log.info("mapData{}", mapData);

        this.sendApplet(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 公众号 低电量通知
     *
     * @param deviceNo
     * @param power
     * @param time
     * @param merchantStoreName
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void officialLowBatteryNotification(
            String deviceNo,
            String power,
            Date time,
            String merchantStoreName,
            User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.VENDING_MACHINE_POWER.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, user.getId(), user.getOfficialAccountId(), pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(user.getOfficialAccountId());


        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", user.getOfficialAccountOpenId());
        JSONObject item = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        keyword1.put("value", deviceNo);
        item.put("character_string4", keyword1);

        JSONObject keyword2 = new JSONObject();
        keyword2.put("value", power);
        item.put("character_string11", keyword2);

        JSONObject keyword3 = new JSONObject();
        keyword3.put("value", merchantStoreName);
        item.put("thing6", keyword3);
        JSONObject keyword4 = new JSONObject();
        keyword4.put("value", sdf.format(time));
        item.put("time22", keyword4);
        jsonObject.put("data", item);
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();
            if (!StringUtils.isEmpty(user.getAppletAccountId())) {
                final AppletOrOfficialAccount appletAccount = appletOrOfficialAccountCommonService.findOneById(user.getAppletAccountId());
                miniprogram.put("appid", appletAccount.getWeChatAppId());
            } else {
                miniprogram.put("appid", configProperties.getWapAppletAppId());
            }
            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), deviceNo));
            jsonObject.put("miniprogram", miniprogram);
        }
        this.sendOfficialAccount(
                jsonObject,
                user.getOfficialAccountOpenId(),
                appletOrOfficialAccount,
                baseUserId,
                user.getId(),
                merchantStoreId,
                pushConfigType
        );
    }


    /**
     * 设备故障通知
     *
     * @param deviceNo
     * @param address
     * @param datetime
     * @param fault
     * @param name
     * @param userId
     * @param merchantStoreId
     */
    @Override
    public void sendFaultMessage(
            String deviceNo,
            String address,
            String datetime,
            Integer fault,
            String name,
            Integer userId,
            Integer merchantStoreId
    ) throws Exception {
        try {
            //用户接受推送消息
            final List<User> userList = userCommonService.findOfficialOrAppletAccountOpenIdByUserId(userId);
            log.info("被通知userIdList：{}", JSON.toJSONString(userList));

            for (User u : userList) {
                log.info("被通知userId：{}", u.getId());
                if (!StringUtils.isEmpty(u.getParentId())) {
                    final MerchantStoreVo merchantStoreVo = merchantStoreCommonService.genOneStoreByParentId(u.getId(), merchantStoreId, AttributeEnum.SUB_ACCOUNT_ADMIN_STORE.getCode());
                    if (StringUtils.isEmpty(merchantStoreVo)) {
                        log.info("子账号没有这场地权限");
                        continue;
                    }
                }

                if (!StringUtils.isEmpty(u.getAppletAccountId()) && !StringUtils.isEmpty(u.getAppletAccountOpenId())) {
                    //小程序推送消息
                    log.info("小程序推送消息");
                    this.appletFaultNotification(deviceNo, address, datetime, name, u.getId(), u.getAppletAccountId(), u.getAppletAccountOpenId(), userId, merchantStoreId);
                }
                if (!StringUtils.isEmpty(u.getOfficialAccountId()) && !StringUtils.isEmpty(u.getOfficialAccountOpenId())) {
                    //公众号推送消息
                    log.info("公众号推送消息");
                    this.accountFaultNotification(deviceNo, name, fault, datetime, address, u, userId, merchantStoreId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorLogCommonService.writerInfoException("设备故障通知发送异常", null, e);
        }
    }

    /**
     * 小程序 设备故障通知
     *
     * @param deviceNo
     * @param address
     * @param datetime
     * @param name
     * @param userId
     * @param appletAccountId
     * @param appletAccountOpenId
     * @param baseUserId
     * @param merchantStoreId
     * @throws Exception
     */
    private void appletFaultNotification(
            String deviceNo,
            String address,
            String datetime,
            String name,
            Integer userId,
            Integer appletAccountId,
            String appletAccountOpenId,
            Integer baseUserId,
            Integer merchantStoreId
    ) throws Exception {
        final int pushConfigType = PushConfigTypeEnum.EQUIPMENT_FAILURE.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(applet, userId, appletAccountId, pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletAccountId);

        //商品故障通知
        JSONObject mapData = new JSONObject();
        JSONObject data = new JSONObject();

        JSONObject d = new JSONObject();
        d.put("value", deviceNo);
        data.put("character_string3", d);

        JSONObject thing2 = new JSONObject();
        thing2.put("value", address);
        data.put("thing2", thing2);

        JSONObject thing7 = new JSONObject();
        thing7.put("value", name);
        data.put("thing7", thing7);

        JSONObject time8 = new JSONObject();
        time8.put("value", datetime);
        data.put("time8", time8);

        JSONObject thing5 = new JSONObject();
        thing5.put("value", "设备故障请及时维修");
        data.put("thing5", thing5);

        mapData.put("template_id", pushConfigVo.getTemplateId());// 模板 id
        mapData.put("touser", appletAccountOpenId); // openId
        mapData.put("data", data); // 数据
        mapData.put("page", ""); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
        mapData.put("miniprogram_state", dev); //developer为开发版；trial为体验版；formal为正式版；默认为正式版
        mapData.put("lang", "zh_CN");
        log.info("mapData{}", mapData);

        this.sendApplet(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                userId,
                merchantStoreId,
                pushConfigType
        );
    }

    /**
     * 公众号 设备故障通知
     *
     * @param deviceNo
     * @param name
     * @param fault
     * @param datetime
     * @param address
     * @param user
     * @param baseUserId
     * @param merchantStoreId
     */
    private void accountFaultNotification(
            String deviceNo,
            String name,
            Integer fault,
            String datetime,
            String address,
            User user,
            Integer baseUserId,
            Integer merchantStoreId
    ) {
        final int pushConfigType = PushConfigTypeEnum.EQUIPMENT_FAILURE.getCode();
        final PushConfigVo pushConfigVo = this.getOnOfOff(officialAccount, user.getId(), user.getOfficialAccountId(), pushConfigType);
        if (!pushConfigVo.getIsOpen()) {
            log.warn("发送前不满足");
            return;
        }

        final AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(user.getOfficialAccountId());

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("template_id", pushConfigVo.getTemplateId());
        jsonObject.put("touser", user.getOfficialAccountOpenId());
        JSONObject item = new JSONObject();
        JSONObject thing5 = new JSONObject();
        thing5.put("value", deviceNo);
        item.put("thing5", thing5);

        JSONObject thing2 = new JSONObject();
        if (StringUtils.isEmpty(name)) {
            name = "-";
        }
        thing2.put("value", name);
        item.put("thing2", thing2);

        JSONObject character_string3 = new JSONObject();
        character_string3.put("value", fault);
        item.put("character_string3", character_string3);

        JSONObject time4 = new JSONObject();
        time4.put("value", datetime);
        item.put("time4", time4);

        JSONObject thing8 = new JSONObject();
        thing8.put("value", address);
        item.put("thing8", thing8);
        log.info(JSON.toJSONString(item));
        if (!StringUtils.isEmpty(pushConfigVo.getAddress())) {
            Map<String, Object> miniprogram = new HashMap();
            if (!StringUtils.isEmpty(user.getAppletAccountId())) {
                final AppletOrOfficialAccount appletAccount = appletOrOfficialAccountCommonService.findOneById(user.getAppletAccountId());
                miniprogram.put("appid", appletAccount.getWeChatAppId());
            } else {
                miniprogram.put("appid", configProperties.getWapAppletAppId());
            }
            miniprogram.put("pagepath", String.format(pushConfigVo.getAddress(), deviceNo));
            jsonObject.put("miniprogram", miniprogram);
        }
        jsonObject.put("data", item);
        this.sendOfficialAccount(
                jsonObject,
                user.getOfficialAccountOpenId(),
                appletOrOfficialAccount,
                baseUserId,
                user.getId(),
                merchantStoreId,
                pushConfigType
        );
    }

    private PushConfigVo getOnOfOff(Integer appletOrOfficialType, Integer userId, Integer appletAccountId, Integer type) {
        PushConfigVo pushConfigVo = pushConfigCommonDao.findOpenOrNotByUserId(userId, type, appletOrOfficialType);
        if (StringUtils.isEmpty(pushConfigVo)) {
            log.warn("未设置开关");
            pushConfigVo = new PushConfigVo();
            pushConfigVo.setIsOpen(false);
            return pushConfigVo;
        }
        if (!pushConfigVo.getIsOpen()) {
            log.warn("已关闭开关");
            pushConfigVo.setIsOpen(false);
            return pushConfigVo;
        }

        PushConfigTemplate condition = new PushConfigTemplate();
        condition.setPushConfigId(pushConfigVo.getId());
        condition.setAppletOrOfficialAccountId(appletAccountId);
        final PushConfigTemplate pushConfigTemplate = pushConfigTemplateCommonService.findOneByCondition(condition);
        if (StringUtils.isEmpty(pushConfigTemplate)) {
            log.warn("未配置模板ID");
            pushConfigVo.setIsOpen(false);
            return pushConfigVo;
        }
        pushConfigVo.setTemplateId(pushConfigTemplate.getTemplateId());
        return pushConfigVo;
    }

    /**
     * 发送通知-1-公众号
     *
     * @param jsonObject
     * @param officialAccountOpenId
     * @param appletOrOfficialAccount
     * @param baseUserId
     * @param subUserId
     * @param merchantStoreId
     * @param pushConfigType
     */
    private void sendOfficialAccount(
            JSONObject jsonObject,
            String officialAccountOpenId,
            AppletOrOfficialAccount appletOrOfficialAccount,
            int baseUserId,
            Integer subUserId,
            int merchantStoreId,
            int pushConfigType
    ) {

        PushRecord pushRecord = this.initPushRecord(
                jsonObject,
                appletOrOfficialAccount,
                baseUserId,
                subUserId,
                merchantStoreId,
                pushConfigType
        );

//        log.info("公众号通知发送成功");
        String errmsg = call(jsonObject, appletOrOfficialAccount.getOfficialAccountAppId(), appletOrOfficialAccount.getOfficialAccountAppSecret());
        log.info("公众号通知发送结果：" + errmsg);
        if (!"ok".equals(errmsg)) {
            //token 失效,刷新Token重发一次
            pushRecord.setResult(PushRecordResultEnum.FAIL.getCode());
            pushRecord.setReason(errmsg);
            if (errmsg.contains("access_token is invalid or not latest")) {
                errmsg = call(jsonObject, appletOrOfficialAccount.getOfficialAccountAppId(), appletOrOfficialAccount.getOfficialAccountAppSecret());
                if (!"ok".equals(errmsg)) {
                    log.error("公众号通知发送失败：{}", officialAccountOpenId);
                    pushRecord.setReason(errmsg);
                } else {
                    pushRecord.setResult(PushRecordResultEnum.SUCCESS.getCode());
                    pushRecord.setReason(null);
                }
            } else {
                log.error("公众号通知发送失败：{}", errmsg);
            }
        } else {
            pushRecord.setResult(PushRecordResultEnum.SUCCESS.getCode());
            log.info("公众号通知发送成功：{}", officialAccountOpenId);
        }
        this.addPushRecord(pushRecord);
    }

    /**
     * 发送通知-2-公众号
     *
     * @param jsonObject
     * @param appId
     * @param appSecret
     * @return
     */
    private String call(JSONObject jsonObject, String appId, String appSecret) {
        log.info("appId：{}", appId);
        final String accessToken = weixinService.getAccessToken(appId, appSecret);

        StringBuffer url = new StringBuffer()
                .append("https://api.weixin.qq.com/cgi-bin/message/template/send?")
                .append("access_token=").append(accessToken);

        //发送公众号通知
        JSONObject result = httpService.httpPost(url.toString(), JSON.toJSONString(jsonObject));
        log.info("公众号通知，模板ID:{}，通知结果:{}", jsonObject.get("template_id"), result.toString());
        return result.getString("errmsg");
    }

    /**
     * 发送通知-小程序
     *
     * @param mapData
     * @param appletOrOfficialAccount
     * @param baseUserId
     * @param subUserId
     * @param merchantStoreId
     * @param pushConfigType
     * @throws Exception
     */
    private void sendApplet(
            JSONObject mapData,
            AppletOrOfficialAccount appletOrOfficialAccount,
            int baseUserId,
            Integer subUserId,
            int merchantStoreId,
            int pushConfigType
    ) throws Exception {
//        log.info("小程序通知发送成功");
        PushRecord pushRecord = this.initPushRecord(
                mapData,
                appletOrOfficialAccount,
                baseUserId,
                subUserId,
                merchantStoreId,
                pushConfigType
        );

        final String redisKey = String.format(RedisKey.WEI_XIN_WAP_APPLET_ACCESS_TOKEN, appletOrOfficialAccount.getWeChatAppId());
        final String accessToken = weChatAppletService.getAccessToken(appletOrOfficialAccount.getWeChatAppId(), appletOrOfficialAccount.getWeChatAppSecret(), redisKey);

        final StringBuffer url = new StringBuffer()
                .append("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?")
                .append("access_token=").append(accessToken);
        JSONObject result = httpService.httpPost(url.toString(), mapData.toString());
        log.info("返回的结果{}", result);
        if ("ok".equals(result.getString("errcode"))) {
            log.info("小程序通知发送成功");
            pushRecord.setResult(PushRecordResultEnum.SUCCESS.getCode());
        } else {
            if ("40001".equals(result.getString("errcode"))) {
                log.warn("access_token过期");
                redisCacheTemplate.delete(redisKey);
            }
            pushRecord.setResult(PushRecordResultEnum.FAIL.getCode());
            pushRecord.setReason(result.getString("errmsg"));
            log.error("小程序通知发送失败:{}", result.getString("errmsg"));
        }
        this.addPushRecord(pushRecord);
    }

    private PushRecord initPushRecord(
            JSONObject mapData,
            AppletOrOfficialAccount appletOrOfficialAccount,
            Integer baseUserId,
            Integer subUserId,
            Integer merchantStoreId,
            Integer pushConfigType
    ) {
        PushRecord pushRecord = new PushRecord();
        pushRecord.setUserId(baseUserId);
        if (!baseUserId.equals(subUserId)) {
            pushRecord.setSubUserId(subUserId);
        }
        pushRecord.setMerchantStoreId(merchantStoreId);
        pushRecord.setPushConfigType(pushConfigType);
        pushRecord.setOrderId(null);
        pushRecord.setActivityOrderId(null);
        pushRecord.setAppletOrOfficialAccountId(appletOrOfficialAccount.getId());
        pushRecord.setContent(JSON.toJSONString(mapData));
        return pushRecord;
    }

    private void addPushRecord(PushRecord pushRecord) {
        pushRecordCommonService.insert(pushRecord);
    }
}
